package com.jrx.anytxn.transaction.service.impl;


import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.customer.dto.customer.CustomerRes;
import com.jrx.anytxn.customer.entity.CmCustomerBankcardInfo;
import com.jrx.anytxn.customer.entity.CmCustomerFirstLevel;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerBankcardInfoMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerFirstLevelMapper;
import com.jrx.anytxn.customer.service.ICustomerService;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrProductTable;
import com.jrx.anytxn.param.service.product.IProductTableService;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.transaction.bean.*;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.dto.chargeoff.TlChargeoffRep;
import com.jrx.anytxn.transaction.dto.chargeoff.TlChargeoffRes;
import com.jrx.anytxn.transaction.entity.*;
import com.jrx.anytxn.transaction.handler.IPaymentHandler;
import com.jrx.anytxn.transaction.mapper.base.TlChargeoffInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.*;
import com.jrx.anytxn.transaction.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ChargeoffServiceImpl implements IChargeoffService {

    private static final Logger logger = LoggerFactory.getLogger(ChargeoffServiceImpl.class);

    @Resource
    private TlChargeoffInfoMapper tlChargeoffInfoMapper;
    @Resource
    private ExtTlChargeoffInfoMapper extTlChargeoffInfoMapper;
    @Autowired
    private ISegmentService segmentService;
    @Resource
    private ExtAmLoanAccountInfoMapper extAmLoanAccountInfoMapper;
    @Resource
    private ExtAmLoanMainInfoMapper extAmLoanMainInfoMapper;
    @Resource
    private ExtCmCustomerFirstLevelMapper extCmCustomerFirstLevelMapper;
    @Autowired
    private IDebtCalculationService debtCalculationService;
    @Autowired
    private IRepaymentPlanService repaymentPlanService;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private IDealDelqService delqService;
    @Resource
    private ExtAmAccountMainInfoMapper extAmAccountMainInfoMapper;
    @Resource
    private ExtAmInterestAccrualInfoMapper extAmInterestAccrualInfoMapper;
    @Resource
    private ExtAmDelinquencyInfoMapper extAmDelinquencyInfoMapper;
    @Resource
    private ExtCmCustomerBankcardInfoMapper extCmCustomerBankcardInfoMapper;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IProductTableService productTableService;
    @Autowired
    private IPaymentLogService paymentLogService;
    @Autowired
    private IGlInterfaceService glInterfaceService;
    @Autowired
    private IPaymentHandler paymentHandler;
    @Resource
    private ExtTlPaymentLogMapper extTlPaymentLogMapper;
    @Resource
    private ExtTlPaymentMappingMapper extTlPaymentMappingMapper;


    @Override
    public TlChargeoffRes addChargeoff(TlChargeoffRep request) throws TxnException {
        //1 判断订单是否已经核销
        List<TlChargeoffInfo> chargeoffInfoList = extTlChargeoffInfoMapper.selectByLoanIdAndResult(request.getLoanId(),request.getTenantId(),request.getCustomerId(),Arrays.asList(TransBizConstant.CHARGEOFF_STATUS_SUC,TransBizConstant.CHARGEOFF_STATUS_D));
        if(CollectionUtils.isNotEmpty(chargeoffInfoList)){
            logger.error("该订单已经核销");
            throw new TxnBizException(TxnRespCode.CHARGEOFF_DATA_EXISTS.getCode(),TxnRespCode.CHARGEOFF_DATA_EXISTS.getUserTips());
        }
        //2 生成主键ID
        TlChargeoffInfo tlChargeoffInfo = BeanMapping.copy(request, TlChargeoffInfo.class);
        tlChargeoffInfo.setTotalOverDueTenor(request.getTotalOverDueTenor());
        tlChargeoffInfo.setIdType(TransBizConstant.ID_TYPE_01);
        try {
            tlChargeoffInfo.setId(segmentService.getId(TransBizConstant.TL_CHARGEOFF_INFO_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        //3 核销初始化状态为D 待核销
        tlChargeoffInfo.setResult(TransBizConstant.CHARGEOFF_STATUS_D);
        tlChargeoffInfo.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        //4 入库
        tlChargeoffInfoMapper.insertSelective(tlChargeoffInfo);
        return BeanMapping.copy(tlChargeoffInfo, TlChargeoffRes.class);
    }

    @Override
    public TxnPage<TlChargeoffRes> getChargeoffByLoanId(String loanId, String tenantId,Integer pageNum,Integer pageSize) throws TxnException {
        Page<TlChargeoffInfo> page = PageHelper.startPage(pageNum, pageSize);

        //1 查询核销消息 可能存在多条核销信息
        List<TlChargeoffInfo> chargeoffInfoList = extTlChargeoffInfoMapper.selectByLoanIdAndTenantId(loanId,tenantId);
        //2 如果存在返回核销订单表数据
        if(CollectionUtils.isEmpty(chargeoffInfoList)){
            logger.error("核销订单不存在，订单编号:{}",loanId);
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }
        List<TlChargeoffRes> res = BeanMapping.copyList(chargeoffInfoList, TlChargeoffRes.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Override
    public TlChargeoffRes processChargeoffByLoanId(String loanId,String tenantId) throws TxnException {
        //1 如果是未核销的订单 查询 贷款信息表
        AmLoanMainInfo amLoanMainInfo  = extAmLoanMainInfoMapper.selectByLoanIdAndTenantId(loanId,tenantId);
        if(amLoanMainInfo == null){
            logger.error("该订单不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }

        //2 判断订单是否已经核销
        List<TlChargeoffInfo> chargeoffInfoList = extTlChargeoffInfoMapper.selectByLoanIdAndResult(loanId,tenantId,amLoanMainInfo.getCustomerId(),Arrays.asList(TransBizConstant.CHARGEOFF_STATUS_SUC,TransBizConstant.CHARGEOFF_STATUS_D));
        if(CollectionUtils.isNotEmpty(chargeoffInfoList)){
            logger.error("该订单已经核销");
            throw new TxnBizException(TxnRespCode.CHARGEOFF_DATA_EXISTS.getCode(),TxnRespCode.CHARGEOFF_DATA_EXISTS.getUserTips());
        }

        //4 查询 贷款账户信息
        AmLoanAccountInfo amLoanAccountInfo = extAmLoanAccountInfoMapper.selectByLoanId(loanId,amLoanMainInfo.getCustomerId(),tenantId);
        if(amLoanAccountInfo == null){
            logger.error("该订单贷款账户不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }
        //5 查询客户一级信息表
        CmCustomerFirstLevel firstLevel = extCmCustomerFirstLevelMapper.selectFirstLevelByOrgIdAndCusId
                (amLoanMainInfo.getCustomerId(),amLoanMainInfo.getOrganizationId(),amLoanMainInfo.getTenantId());
        if(firstLevel == null){
            logger.error("客户信息不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }
        //6 获取当前业务日期
        PrOrganizationTable org = organizationTableService.findByOrId(amLoanMainInfo.getOrganizationId(), amLoanMainInfo.getTenantId());
        Date bussinessDate = org.getNextProcessingDate();

        //7 获取订单未抛、正常、逾期状态的还款计划
        List<AmRepaymentPlanInfo> repaymentPlanInfos = repaymentPlanService.getPlanList(amLoanMainInfo.getLoanId(),
                amLoanMainInfo.getCustomerId(), amLoanMainInfo.getTenantId(),
                Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_0, TransBizConstant.LOAN_PLAN_STATUS_1,
                        TransBizConstant.LOAN_PLAN_STATUS_2));
        //8 欠款计算
        DebtBean debtBean = debtCalculationService.getBalance(amLoanAccountInfo, repaymentPlanInfos, bussinessDate, null, null, null, false);
        if (debtBean.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
            String errMsg =
                    TxnRespCode.PAYMENT_DEBT_AMOUNT_ZERO.getFormatMsg(amLoanAccountInfo.getLoanId(), debtBean.getTotalAmount().toString());
            logger.error(errMsg);
            throw new TxnBizException(TxnRespCode.PAYMENT_DEBT_AMOUNT_ZERO.getCode(), TxnRespCode.PAYMENT_DEBT_AMOUNT_ZERO.getUserTips());

        }
        return createChargeoffInfo(amLoanMainInfo,amLoanAccountInfo,firstLevel,debtBean,bussinessDate);
    }

    @Override
    public TlChargeoffRes editChargeoff(TlChargeoffRep request) throws TxnException {
        //1 判断订单是否已经核销
        TlChargeoffInfo chargeoffInfo = extTlChargeoffInfoMapper.selectByIdAndTenantId(request.getTenantId(),request.getCustomerId(),request.getId());
        if(null == chargeoffInfo){
            logger.error("核销订单不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }
        TlChargeoffInfo update = BeanMapping.copy(request,TlChargeoffInfo.class);
        //2 修改核销原因码 与 描述
        extTlChargeoffInfoMapper.updateCodeByLoanIdAndTenantId(update);
        return BeanMapping.copy(request, TlChargeoffRes.class);
    }

    @Override
    public Boolean removeByTenIdAndLoanId(String tenantId,String customerId, Long id) throws TxnException {
        //1 判断核销订单是否存在
        TlChargeoffInfo chargeoffInfo = extTlChargeoffInfoMapper.selectByIdAndTenantId(tenantId,customerId,id);
        if(null == chargeoffInfo){
            logger.error("核销订单不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }

        //2 判断核销状态 只允许删除待核销的订单
        if(!TransBizConstant.CHARGEOFF_STATUS_D.equals(chargeoffInfo.getResult())){
            logger.error("只允许删除待核销的订单");
            throw new TxnException(TxnRespCode.ERROR.getUserTips());
        }
        //3 删除核销订单
        int i = extTlChargeoffInfoMapper.deleteByTenantIdAndLoanId(chargeoffInfo.getTenantId(),id,chargeoffInfo.getCustomerId());
        return i > 0;
    }

    private TlChargeoffRes createChargeoffInfo(AmLoanMainInfo amLoanMainInfo, AmLoanAccountInfo amLoanAccountInfo, CmCustomerFirstLevel firstLevel,
                                               DebtBean debtBean, Date bussinessDate){
        TlChargeoffRes tlChargeoffRes = new TlChargeoffRes();
        tlChargeoffRes.setLoanId(amLoanMainInfo.getLoanId());
        tlChargeoffRes.setOrganizationId(amLoanMainInfo.getOrganizationId());
        tlChargeoffRes.setTenantId(amLoanMainInfo.getTenantId());
        tlChargeoffRes.setChannel(amLoanMainInfo.getChannel());
        tlChargeoffRes.setProductId(amLoanMainInfo.getProductId());
        tlChargeoffRes.setCustomerId(amLoanMainInfo.getCustomerId());
        tlChargeoffRes.setIdNumber(firstLevel.getIdNumber());
        tlChargeoffRes.setIdType(firstLevel.getIdType());
        tlChargeoffRes.setChineseName(firstLevel.getChineseName());
        tlChargeoffRes.setChargeoffAmount(debtBean.getTotalAmount());//核销金额
        tlChargeoffRes.setChargeoffPrincipal(debtBean.getPrincipalAmount());
        tlChargeoffRes.setChargeoffInterest(debtBean.getInterestAmount());
        tlChargeoffRes.setChargeoffPenalty(debtBean.getPenaltyAmount());
        tlChargeoffRes.setChargeoffCompound(debtBean.getCompountAmount());
        tlChargeoffRes.setChargeoffFee(debtBean.getFeeAmount());
        tlChargeoffRes.setChargeoffDate(bussinessDate);
        tlChargeoffRes.setDelqDays(amLoanAccountInfo.getDelqDays());
        tlChargeoffRes.setTotalOverDueTenor(amLoanAccountInfo.getTotalOverDueTenor());
        return tlChargeoffRes;
    }

    @Override
    public ChargeoffBean processChargeoff(TlChargeoffInfo tlChargeoffInfo) throws Exception {
        ChargeoffBean chargeoffBean = new ChargeoffBean();

        List<AmRepaymentPlanInfo> updatePlanList = new ArrayList<>();
        List<AmAccountMainInfo> saveAcctList = new ArrayList<>();
        List<TlGlInterfaceInfo> saveGlList = new ArrayList<>();
        List<AmAccountMainInfo> updateAcctList = new ArrayList<>();
        List<AmInterestAccrualInfo> updateInterAcctList = new ArrayList<>();
        List<AmDelinquencyInfo> updateAmDelinquencyInfoList = new ArrayList<>();
        List<TlTransactionInfo> saveTlTransactionInfoList = new ArrayList<>();

        logger.info("核销处理开始，订单号：{}",tlChargeoffInfo.getLoanId());
        String customerId = tlChargeoffInfo.getCustomerId();
        String loanId = tlChargeoffInfo.getLoanId();
        String tenantId = tlChargeoffInfo.getTenantId();
        String organizationId = tlChargeoffInfo.getOrganizationId();
        String channel = tlChargeoffInfo.getChannel();

        //获取当前业务日期
        PrOrganizationTable org = organizationTableService.findByOrId(organizationId, tenantId);
        Date bussinessDate = org.getNextProcessingDate();

        //1 核销数据校验
        //订单有是否有还款中信息
        if(paymentHandler.repaymentLogStatusFlag(loanId, customerId,tenantId) || paymentHandler.repaymentWaiveLogStatusFlag(loanId,customerId,tenantId)){
            logger.info("订单还款处理中，核销失败，订单编号：{}",tlChargeoffInfo.getLoanId());
            tlChargeoffInfo.setResult(TransBizConstant.CHARGEOFF_STATUS_FAIL);
            tlChargeoffInfo.setResultDesc("订单还款处理中，核销失败");
            chargeoffBean.setUpdateTlChargeoffInfo(tlChargeoffInfo);
            return chargeoffBean;
        }
        //检查贷款账户表 核销状态
        AmLoanMainInfo amLoanMainInfo = extAmLoanMainInfoMapper.selectByLoanId(loanId,customerId,tenantId,channel);

        AmLoanAccountInfo amLoanAccountInfo = extAmLoanAccountInfoMapper.selectByLoanId(loanId,customerId,tenantId);
        if(TransBizConstant.YES_FLAG.equals(amLoanAccountInfo.getChargeoffFlag())){
            logger.info("订单已经核销，订单号：{}",tlChargeoffInfo.getLoanId());
            tlChargeoffInfo.setResult(TransBizConstant.CHARGEOFF_STATUS_FAIL);
            tlChargeoffInfo.setResultDesc("订单已经核销");
            chargeoffBean.setUpdateTlChargeoffInfo(tlChargeoffInfo);
            return chargeoffBean;
        }

        //2 更新订单账户信息
        AmLoanAccountInfo updateLoanAcc = new AmLoanAccountInfo();
        updateLoanAcc.setId(amLoanAccountInfo.getId());
        updateLoanAcc.setCustomerId(amLoanAccountInfo.getCustomerId());
        updateLoanAcc.setLoanId(amLoanAccountInfo.getLoanId());
        updateLoanAcc.setTenantId(amLoanAccountInfo.getTenantId());
        updateLoanAcc.setChargeoffAmount(tlChargeoffInfo.getChargeoffAmount());//核销金额
        updateLoanAcc.setChargeoffFlag(TransBizConstant.YES_FLAG);//核销标志
        updateLoanAcc.setChargeoffDate(bussinessDate);//核销日期
        updateLoanAcc.setChargeoffReasonCode(tlChargeoffInfo.getChargeoffReasonCode());//核销原因码
        updateLoanAcc.setWaiveFeeFlag(TransBizConstant.WAIVE_FEE_FLAG_0);//停费标识
        updateLoanAcc.setWaiveInterestFlag(TransBizConstant.WAIVE_INTEREST_FLAG_0);//停息标识


        //3 更新还款计划 未到期还款计划需要抛账
        List<AmRepaymentPlanInfo> repaymentPlanInfos = repaymentPlanService.getPlanList(loanId,
                customerId, tenantId,
                Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_0, TransBizConstant.LOAN_PLAN_STATUS_1,
                        TransBizConstant.LOAN_PLAN_STATUS_2));

        for(AmRepaymentPlanInfo planInfo : repaymentPlanInfos){
            AmRepaymentPlanInfo updatePlanInfo = new AmRepaymentPlanInfo();
            updatePlanInfo.setId(planInfo.getId());
            updatePlanInfo.setCustomerId(planInfo.getCustomerId());
            updatePlanInfo.setTenantId(planInfo.getTenantId());
            updatePlanInfo.setChargeoffFlag(TransBizConstant.YES_FLAG);//核销标识

            if(planInfo.getPlanStatus().equals(TransBizConstant.LOAN_PLAN_STATUS_0)){
                updatePlanInfo.setPlanStatus(TransBizConstant.LOAN_PLAN_STATUS_1);//修改计划状态为 1 正常
                //抛账 抛出本金交易账户
                DelqParamBean delqParamBean = delqService.buildDqlqAccountBean(amLoanMainInfo.getTenantId(),amLoanMainInfo.getDelqTableId());
                CastAccountTransactionBean accBean = accountService.castPrincipalAccountByChargeoff(amLoanMainInfo, amLoanAccountInfo, planInfo, delqParamBean, bussinessDate);
                AmAccountMainInfo amAccountMainInfo = accBean.getAmAccountMainInfo();
                saveAcctList.add(amAccountMainInfo);
                if(CollectionUtils.isNotEmpty(accBean.getTlGlInterfaceInfoList())){
                    saveGlList.addAll(accBean.getTlGlInterfaceInfoList());
                }
                saveTlTransactionInfoList.add(accBean.getTlTransactionInfo());
                //还需生成一条原GL流水
                TlGlInterfaceInfo tlGlInterfaceInfo = glInterfaceService.buildTlGlInterfaceInfo(amAccountMainInfo, amAccountMainInfo.getCurrBalance(), TransBizConstant.TXN_CODE_INST, amAccountMainInfo.getAccountingPhase(), bussinessDate);
                if(null != tlGlInterfaceInfo){
                    saveGlList.add(tlGlInterfaceInfo);
                }
            }
            updatePlanList.add(updatePlanInfo);
        }
        //4 获取已经抛账交易账户 本金 利息 罚息 复利 费用
        List<AmAccountMainInfo> acctList = extAmAccountMainInfoMapper.selectAccounts(loanId,
                Arrays.asList(TransBizConstant.ACCOUNT_TYPE_04, TransBizConstant.ACCOUNT_TYPE_06,
                        TransBizConstant.ACCOUNT_TYPE_11, TransBizConstant.ACCOUNT_TYPE_12 ,TransBizConstant.ACCOUNT_TYPE_03),
                customerId,tenantId,Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2));
        if(!CollectionUtils.isEmpty(acctList)){
            for(AmAccountMainInfo account: acctList){
                AmAccountMainInfo updateAmAccountMainInfo = new AmAccountMainInfo();
                updateAmAccountMainInfo.setId(account.getId());
                updateAmAccountMainInfo.setCustomerId(account.getCustomerId());
                updateAmAccountMainInfo.setTenantId(account.getTenantId());
                updateAmAccountMainInfo.setChargeoffFlag(TransBizConstant.YES_FLAG);//核销标识
                updateAmAccountMainInfo.setWaiveFeeFlag(TransBizConstant.WAIVE_FEE_FLAG_0);
                updateAmAccountMainInfo.setWaiveInterestFlag(TransBizConstant.WAIVE_INTEREST_FLAG_0);
                updateAmAccountMainInfo.setChargeoffAmount(account.getPostingAmount());
                updateAmAccountMainInfo.setChargeoffDate(bussinessDate);
                updateAmAccountMainInfo.setChargeoffReasonCode(tlChargeoffInfo.getChargeoffReasonCode());
                String taxTxnCode = "";
                String txnCode = "";
                if(account.getAccountType().equals(TransBizConstant.ACCOUNT_TYPE_06)){
                    txnCode = TransBizConstant.TXN_CHARGEOFF_CODE_PRINCIPAL;
                }else if(account.getAccountType().equals(TransBizConstant.ACCOUNT_TYPE_04)){
                    txnCode = TransBizConstant.TXN_CHARGEOFF_CODE_INTR;
                    taxTxnCode = TransBizConstant.TXN_CHARGEOFF_CODE_INTR_TAX;
                }else if(account.getAccountType().equals(TransBizConstant.ACCOUNT_TYPE_11)) {
                    txnCode = TransBizConstant.TXN_CHARGEOFF_CODE_PEN_INTR;
                    taxTxnCode = TransBizConstant.TXN_CHARGEOFF_CODE_PEN_INTR_TAX;
                }else if(account.getAccountType().equals(TransBizConstant.ACCOUNT_TYPE_12)) {
                    txnCode = TransBizConstant.TXN_CHARGEOFF_CODE_COMP_INTR;
                    taxTxnCode = TransBizConstant.TXN_CHARGEOFF_CODE_COMP_INTR_TAX;
                }else if(account.getAccountType().equals(TransBizConstant.ACCOUNT_TYPE_03)) {
                    txnCode = TransBizConstant.TXN_CHARGEOFF_CODE_FEE;
                }

                //生成一条核销GL流水
                TlGlInterfaceInfo tlGlInterfaceInfo = glInterfaceService.buildTlGlInterfaceInfo(account, account.getCurrBalance().subtract(account.getTaxAmt()), txnCode, account.getAccountingPhase(), bussinessDate);
                //生成税金gl
                TlGlInterfaceInfo taxTlGlInterfaceInfo = glInterfaceService.buildTlGlInterfaceInfo(account, account.getTaxAmt(), taxTxnCode, account.getAccountingPhase(), bussinessDate);
                if(null != tlGlInterfaceInfo){
                    saveGlList.add(tlGlInterfaceInfo);
                }
                if(null != taxTlGlInterfaceInfo){
                    saveGlList.add(taxTlGlInterfaceInfo);
                }
                updateAcctList.add(updateAmAccountMainInfo);
            }
        }

        //5 获取利息/罚息/罚息复利累计
        List<AmInterestAccrualInfo> accuAcctList = extAmInterestAccrualInfoMapper.selectAllAccuAcct(
                loanId, customerId, tenantId, Arrays.asList(TransBizConstant.INTEREST_ACCRUAL_TYPE_66,
                        TransBizConstant.INTEREST_ACCRUAL_TYPE_10,TransBizConstant.INTEREST_ACCRUAL_TYPE_20), Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_1));
        if(!CollectionUtils.isEmpty(accuAcctList)){
            for(AmInterestAccrualInfo intrAccInfo : accuAcctList){
                AmInterestAccrualInfo updateAmInterestAccrualInfo = new AmInterestAccrualInfo();
                updateAmInterestAccrualInfo.setId(intrAccInfo.getId());
                updateAmInterestAccrualInfo.setCustomerId(intrAccInfo.getCustomerId());
                updateAmInterestAccrualInfo.setTenantId(intrAccInfo.getTenantId());
                updateAmInterestAccrualInfo.setAccountStatus(TransBizConstant.ACCOUNT_STATUS_8);
                updateAmInterestAccrualInfo.setStopAccrualFlag(TransBizConstant.STOP_ACCRU_FLAG_1);
                updateInterAcctList.add(updateAmInterestAccrualInfo);
                CastAccountTransactionBean intrCastAccrt = accountService.castInterestAccountByChargeoff(amLoanMainInfo, amLoanAccountInfo,
                        intrAccInfo, bussinessDate,tlChargeoffInfo.getChargeoffReasonCode());

                AmAccountMainInfo intrInfo = intrCastAccrt.getAmAccountMainInfo();
                saveAcctList.add(intrInfo);
                if(CollectionUtils.isNotEmpty(intrCastAccrt.getTlGlInterfaceInfoList())){
                    saveGlList.addAll(intrCastAccrt.getTlGlInterfaceInfoList());
                }
                if(null != intrCastAccrt.getTlTransactionInfo()){
                    saveTlTransactionInfoList.add(intrCastAccrt.getTlTransactionInfo());
                }
            }
        }

        //6 获查询 延滞信息表
        List<AmDelinquencyInfo> listDelp = extAmDelinquencyInfoMapper.selectDelqInfoByLoanId(loanId,customerId,tenantId,Arrays.asList(TransBizConstant.ACCOUNT_STATUS_0,TransBizConstant.ACCOUNT_STATUS_1));
        if(!CollectionUtils.isEmpty(listDelp)){
            for(AmDelinquencyInfo delpInfo : listDelp){
                AmDelinquencyInfo updateAmDelinquencyInfo = new AmDelinquencyInfo();
                updateAmDelinquencyInfo.setId(delpInfo.getId());
                updateAmDelinquencyInfo.setCustomerId(delpInfo.getCustomerId());
                updateAmDelinquencyInfo.setTenantId(delpInfo.getTenantId());
                updateAmDelinquencyInfo.setChargeoffFlag(TransBizConstant.YES_FLAG);
                updateAmDelinquencyInfoList.add(updateAmDelinquencyInfo);
            }
        }

        //7 更新核销订单表
        tlChargeoffInfo.setResult(TransBizConstant.CHARGEOFF_STATUS_SUC);

        //8 更新借据表余额
        updateLoanAcc.setCurrBalance(amLoanAccountInfo.getCurrBalance());
        updateLoanAcc.setPrincipalBalance(amLoanAccountInfo.getPrincipalBalance());
        updateLoanAcc.setInterestBalance(amLoanAccountInfo.getInterestBalance());
        updateLoanAcc.setPenaltyBalance(amLoanAccountInfo.getPenaltyBalance());
        updateLoanAcc.setCompoundBalance(amLoanAccountInfo.getCompoundBalance());
        updateLoanAcc.setAccruedInterest(amLoanAccountInfo.getAccruedInterest());
        updateLoanAcc.setAccruedPenalty(amLoanAccountInfo.getAccruedPenalty());
        updateLoanAcc.setAccruedCompound(amLoanAccountInfo.getAccruedCompound());

        chargeoffBean.setUpdateTlChargeoffInfo(tlChargeoffInfo);
        chargeoffBean.setUpdateAmLoanAccountInfo(updateLoanAcc);
        chargeoffBean.setSaveAcctList(saveAcctList);
        chargeoffBean.setUpdateAmRepaymentPlanInfoList(updatePlanList);
        chargeoffBean.setSaveTlGlInterfaceInfoList(saveGlList);
        chargeoffBean.setUpdateAmAccountMainInfoList(updateAcctList);
        chargeoffBean.setUpdateAmDelinquencyInfoList(updateAmDelinquencyInfoList);
        chargeoffBean.setUpdateAmInterestAccrualInfoList(updateInterAcctList);
        chargeoffBean.setInsertTlTransactionInfoList(saveTlTransactionInfoList);

        return chargeoffBean;
    }

    @Override
    public ChargeoffPaymentBean chargeoffPay(TlChargeoffInfo tlChargeoffInfo) throws Exception {
        logger.info("核销批量扣款开始：订单号：{}",tlChargeoffInfo.getLoanId());
        ChargeoffPaymentBean chargeoffPaymentBean = new ChargeoffPaymentBean();

        List<TlPaymentLog> tlPaymentLogList = new ArrayList<>();
        List<TlPaymentMapping> tlPaymentMappingList = new ArrayList<>();

        String loanId = tlChargeoffInfo.getLoanId();
        String customerId = tlChargeoffInfo.getCustomerId();
        String tenantId = tlChargeoffInfo.getTenantId();
        String channel = tlChargeoffInfo.getChannel();
        String productId = tlChargeoffInfo.getProductId();
        String organizationId = tlChargeoffInfo.getOrganizationId();

        //获取当前业务日期
        PrOrganizationTable org = organizationTableService.findByOrId(organizationId, tenantId);
        Date bussinesDate = org.getNextProcessingDate();

        //1 根据订单查询 订单账户信息 如果已经结清无需处理
        AmLoanAccountInfo amLoanAccountInfo = extAmLoanAccountInfoMapper.selectByLoanIdAndAccountStatus(loanId,customerId,tenantId,
                Arrays.asList(TransBizConstant.LOAN_STATUS_1,TransBizConstant.LOAN_STATUS_2));
        if(amLoanAccountInfo == null){
            logger.info("当前订单已经结清无需处理：订单号：{}",tlChargeoffInfo.getLoanId());
            return null;
        }

        //2 判断是否存在扣款处理中
        List<String> sumStatusList = Arrays.asList(TransBizConstant.PAYMENT_LOG_SUM_STATUS_O,
                TransBizConstant.PAYMENT_LOG_SUM_STATUS_T, TransBizConstant.PAYMENT_LOG_SUM_STATUS_D);
        List<TlPaymentLog> seqList =
                extTlPaymentLogMapper.selectListBySumStatusForBatch(customerId,
                        channel,sumStatusList);
        //还款流水不空 与订单匹配
        if(CollectionUtils.isNotEmpty(seqList)){
            List<String> seqNoList = seqList.stream().map(TlPaymentLog::getSeqNo).collect(Collectors.toList());
            //获取还款流水对应的订单信息
            List<String> loanIdList = extTlPaymentMappingMapper.selectBySeqNoListForBatch(seqNoList);
            //剔除正在还款中的数据
            if(loanIdList.contains(amLoanAccountInfo.getLoanId())){
                return null;
            }
        }

        //3 获取客户当前渠道默认扣款卡
        CmCustomerBankcardInfo bank = extCmCustomerBankcardInfoMapper.selectBankCardByCondition(
                customerId,TransBizConstant.Y_FLAG,null,channel,tenantId);
        if( bank == null ){//不存在默认还款卡
            return  null;
        }

        //4 查询客户信息
        CustomerRes customer = customerService.getCustomerByChannelAndCustomerIdAndTensnId(channel,
                customerId,tenantId);

        //5 查询产品信息
        PrProductTable product =
                productTableService.findProByProIdAndOrgId(productId,organizationId,tenantId);

        //6 从新计算订单欠款
        List<AmRepaymentPlanInfo> repaymentPlanInfos = repaymentPlanService.getPlanList(loanId,
                customerId, tenantId,
                Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_0, TransBizConstant.LOAN_PLAN_STATUS_1,
                        TransBizConstant.LOAN_PLAN_STATUS_2));

        DebtBean debtBean = debtCalculationService.getBalance(amLoanAccountInfo, repaymentPlanInfos, bussinesDate, null, null, null, false);
        if(debtBean.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0){
            //没有欠款
            return null;
        }

        //7 构建还款流水
        TlPaymentLog tlPaymentLog =
                paymentLogService.buildTlPaymentLog(TransBizConstant.REPAYMENT_TYPE_CHARGEOFF,
                        bank, customer, debtBean.getTotalAmount(), bussinesDate, product, null);
        tlPaymentLog.setIsFullPay(TransBizConstant.IS_FULL_PAY_0);//核销支持非足额扣款
        tlPaymentLogList.add(tlPaymentLog);

        //8 还款流水与订单映射信息
        TlPaymentMapping tlPaymentMapping = paymentLogService.buildTlPaymentMapping(customerId,
                tlPaymentLog.getSeqNo(),loanId,tenantId);
        tlPaymentMappingList.add(tlPaymentMapping);



        chargeoffPaymentBean.setSaveTlPaymentLogList(tlPaymentLogList);
        chargeoffPaymentBean.setSaveTlPaymentMapping(tlPaymentMappingList);

        return chargeoffPaymentBean;
    }

    @Override
    public TlChargeoffRes getChargeoffById(Long id, String customerId, String tenantId) throws TxnException {
        //1 判断订单是否已经核销
        TlChargeoffInfo chargeoffInfo = extTlChargeoffInfoMapper.selectByIdAndTenantId(tenantId,customerId,id);
        if(null == chargeoffInfo){
            logger.error("核销订单不存在");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(),TxnRespCode.NO_DATA.getMsg());
        }
        return BeanMapping.copy(chargeoffInfo, TlChargeoffRes.class);
    }
}
